package com.ruoyi.bussiness.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.Schedule;
import com.ruoyi.system.domain.vo.ScheduleVo;
import com.ruoyi.system.domain.bo.AssessmentBo;
import com.ruoyi.system.domain.bo.AttendanceBo;
import com.ruoyi.system.domain.bo.PoliceOfficerBo;
import com.ruoyi.system.domain.bo.ShiftBo;
import com.ruoyi.system.domain.vo.AssessmentVo;
import com.ruoyi.system.domain.vo.AttendanceVo;
import com.ruoyi.system.domain.vo.PoliceOfficerVo;
import com.ruoyi.system.domain.vo.ShiftVo;
import com.ruoyi.system.domain.vo.PatrolAreaUserVo;
import com.ruoyi.system.domain.vo.PatrolAreaVo;
import com.ruoyi.system.domain.vo.PostVo;
import com.ruoyi.system.domain.bo.PostBo;
import com.ruoyi.system.service.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import lombok.RequiredArgsConstructor;
import lombok.Data;
import org.springframework.web.bind.annotation.*;
import java.util.stream.Collectors;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能排班系统Controller
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/bussiness/scheduling")
@RequiredArgsConstructor
public class SchedulingController extends BaseController {

    /**
     * 巡区分配信息内部类
     */
    @Data
    public static class PatrolAreaAssignment {
        private Long areaId;
        private String areaName;
        private String areaType;
        private List<SysUser> assignedUsers;
        private List<PostVo> availablePosts;
        private String patrolRoute;
    }

    private final IScheduleService scheduleService;

    private final DeepSeekService deepSeekService;

    private final IShiftService shiftService;

    private final IAttendanceService attendanceService;

    private final IAssessmentService assessmentService;
    private final IPoliceOfficerService policeOfficerService;
    private final IPatrolAreaUserService patrolAreaUserService;
    private final IPatrolAreaService patrolAreaService;
    private final IPostService postService;

    private final ISysUserService sysUserService;

    /**
     * 查询排班列表
     */
    @GetMapping("/list")
    public R<List<Schedule>> list(Schedule schedule) {
        List<Schedule> list = scheduleService.selectScheduleList(schedule);
        return R.ok(list);
    }

    /**
     * 获取算法推荐参数
     */
    @GetMapping("/algorithm/params")
    public R<Map<String, Object>> getAlgorithmParams() {
        Map<String, Object> params = scheduleService.getRecommendedAlgorithmParams();
        return R.ok(params);
    }

    @PostMapping("/person-adjust")
    public R<Void> personAdjust(@RequestBody Schedule schedule) {
        return scheduleService.personAdjust(schedule) ? R.ok() : R.ok("人员调整失败");
    }

    @DeleteMapping("/delete/{id}")
    public R<Void> delete(@PathVariable Long id) {
        return scheduleService.delete(id) ? R.ok() : R.ok("删除失败");
    }

    /**
     * 生成智能排班
     */
    @SaCheckRole("admin")
    @Log(title = "智能排班", businessType = BusinessType.INSERT)
    @PostMapping("/generate")
    public R<Void> generate(@RequestBody Map<String, Object> params) {
        // 执行智能排班算法
        boolean success = scheduleService.generateSchedule(params);
        return success ? R.ok() : R.ok("智能排班生成失败");
    }


    /**
     * 调整排班
     */
    @Log(title = "调整排班", businessType = BusinessType.UPDATE)
    @PutMapping("/adjust")
    public R<Void> adjust(@RequestBody Map<String, Object> params) {
        // 执行排班调整
        boolean success = scheduleService.adjustSchedule(params);
        return success ? R.ok() : R.ok("排班调整失败");
    }

    /**
     * 获取警员出勤统计
     */
    @GetMapping("/stats/{officerId}")
    public R<Map<String, Object>> getOfficerStats(@PathVariable Long officerId) {
        Map<String, Object> stats = scheduleService.selectOfficerAttendanceStats(officerId);
        return R.ok(stats);
    }

    @PostMapping("/ai/generate")
    public R<Void> generateByAI(@RequestBody JSONObject params) {
        try {
            // � 修复：处理空日期参数，设置默认值
            String startDate = params.getStr("startDate", "");
            String endDate = params.getStr("endDate", "");

            if (startDate.isEmpty()) {
                startDate = LocalDate.now().toString();
                System.out.println("🔧 开始日期为空，设置默认值: " + startDate);
            }
            if (endDate.isEmpty()) {
                endDate = LocalDate.now().plusDays(1).toString();
                System.out.println("🔧 结束日期为空，设置默认值: " + endDate);
            }

            System.out.println("📅 处理后的日期参数 - 开始日期: " + startDate + ", 结束日期: " + endDate);

            // 🔥 关键改进：在开始生成前，先清理指定日期范围的所有记录
            if (!startDate.isEmpty() && !endDate.isEmpty()) {
                System.out.println("🧹 开始清理日期范围 " + startDate + " 到 " + endDate + " 的所有排班记录...");
                cleanupDateRangeSchedules(startDate, endDate);
            }

            // 执行智能排班算法
            List<SysUser> sysUsers = sysUserService.selectUserList(new SysUser());

            // 智能分批处理：按部门和区域分组生成排班
            Long officerId = params.getLong("officerId");
            List<SysUser> allUsers = sysUsers;

            if (officerId != null && officerId > 0) {
                // 只为指定警员生成排班
                allUsers = sysUsers.stream().filter(k -> k.getUserId().equals(officerId)).collect(Collectors.toList());
            }

            // 基于巡区负责人进行排班分析（只执行一次）
            Map<Long, PatrolAreaAssignment> areaAssignmentMap = analyzePatrolAreaAssignments();

            // 筛选出有负责人的巡区和对应的用户
            List<SysUser> assignedUsers = new ArrayList<>();
            Map<Long, String> officerAreaMap = new HashMap<>();
            Map<Long, String> officerRouteMap = new HashMap<>();

            for (PatrolAreaAssignment assignment : areaAssignmentMap.values()) {
                if (!assignment.getAssignedUsers().isEmpty()) {
                    for (SysUser user : assignment.getAssignedUsers()) {
                        assignedUsers.add(user);
                        officerAreaMap.put(user.getUserId(),
                            assignment.getAreaName() + "(" + assignment.getAreaType() + ")");
                        officerRouteMap.put(user.getUserId(), assignment.getPatrolRoute());
                    }
                }
            }

            if (assignedUsers.isEmpty()) {
                System.out.println("⚠️ 没有找到已分配巡区的负责人，无法进行AI排班");
                return R.ok("没有找到已分配巡区的负责人");
            }

            System.out.println("🎯 找到 " + assignedUsers.size() + " 个已分配巡区的负责人，开始AI排班");

            List<Schedule> allSchedules = new ArrayList<>();

            // 设置排班参数
            params.put("startDate", startDate);
            params.put("endDate", endDate);

            // 为有巡区分配的用户生成排班
            List<Schedule> schedules = generateScheduleForAssignedUsers(assignedUsers, params, officerAreaMap, officerRouteMap);
            allSchedules.addAll(schedules);

            // 验证排班完整性
            int dayCount = calculateDaysBetween(startDate, endDate);
            int expectedTotal = allUsers.size() * dayCount;

            System.out.println("=== 排班生成完成统计 ===");
            System.out.println("总警员数: " + allUsers.size());
            System.out.println("排班天数: " + dayCount + " 天 (" + startDate + " 到 " + endDate + ")");
            System.out.println("预期排班记录数: " + expectedTotal);
            System.out.println("实际生成记录数: " + allSchedules.size());

            // 检查每个警员是否都有排班
            Map<Long, Integer> officerScheduleCount = new HashMap<>();
            for (Schedule schedule : allSchedules) {
                officerScheduleCount.merge(schedule.getOfficerId(), 1, Integer::sum);
            }

            List<String> missingOfficers = new ArrayList<>();
            for (SysUser user : allUsers) {
                int scheduleCount = officerScheduleCount.getOrDefault(user.getUserId(), 0);
                if (scheduleCount == 0) {
                    missingOfficers.add(user.getNickName() + "(ID:" + user.getUserId() + ")");
                } else if (scheduleCount < dayCount) {
                    System.out.println("警员 " + user.getNickName() + " 排班不完整: " + scheduleCount + "/" + dayCount + " 天");
                }
            }

            if (!missingOfficers.isEmpty()) {
                System.out.println("⚠️ 以下警员没有生成排班: " + String.join(", ", missingOfficers));
            }

            // 排班已经在按天生成时保存了，这里只做统计
            if (!allSchedules.isEmpty()) {
                System.out.println("✅ 排班保存成功！总共生成了 " + allSchedules.size() + " 条排班记录");

                if (allSchedules.size() == expectedTotal) {
                    System.out.println("🎉 所有警员排班生成完整！");
                } else {
                    System.out.println("⚠️ 排班生成不完整，可能需要重新生成缺失的部分");
                }
            } else {
                System.out.println("❌ 没有生成任何排班记录");
                return R.fail("排班生成失败，请检查AI服务或重试");
            }

            return R.ok();
        } catch (Exception e) {
            System.out.println("AI排班生成失败: " + e.getMessage());
            e.printStackTrace();
            return R.fail("AI排班生成失败，请稍后重试");
        }
    }

    /**
     * 为有巡区分配的用户生成排班
     */
    private List<Schedule> generateScheduleForAssignedUsers(List<SysUser> assignedUsers, JSONObject params,
                                                          Map<Long, String> officerAreaMap, Map<Long, String> officerRouteMap) {
        List<Schedule> schedules = new ArrayList<>();

        try {
            // 获取班次数据
            ShiftBo shiftBo = new ShiftBo();
            List<ShiftVo> shiftVoList = shiftService.queryList(shiftBo);

            // 获取历史排班经验
            Schedule querySchedule = new Schedule();
            List<Schedule> existingSchedules = scheduleService.selectScheduleList(querySchedule);
            Map<Long, Integer> officerExperienceMap = new HashMap<>();
            if (existingSchedules != null && !existingSchedules.isEmpty()) {
                Map<Long, List<Schedule>> tempMap = existingSchedules.stream()
                    .filter(s -> s != null && s.getOfficerId() != null)
                    .limit(20)
                    .collect(Collectors.groupingBy(Schedule::getOfficerId));

                for (Map.Entry<Long, List<Schedule>> entry : tempMap.entrySet()) {
                    officerExperienceMap.put(entry.getKey(), Math.min(entry.getValue().size(), 3));
                }
            }

            // 按日期生成排班
            String startDate = params.getStr("startDate");
            String endDate = params.getStr("endDate");

            LocalDate start = LocalDate.parse(startDate);
            LocalDate end = LocalDate.parse(endDate);

            for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) {
                String targetDate = date.toString();
                System.out.println("生成 " + targetDate + " 的排班...");

                // 构建单日排班提示词
                String dailyPrompt = buildDailyPromptForAssignedUsers(assignedUsers, shiftVoList, targetDate,
                    officerExperienceMap, officerAreaMap, officerRouteMap);

                // 调用AI接口
                String result = deepSeekService.askAI(dailyPrompt);

                // 处理单日排班结果
                processDailyScheduleResult(result, schedules, assignedUsers, targetDate, params, officerRouteMap, officerAreaMap);
            }

        } catch (Exception e) {
            System.out.println("为已分配用户生成排班失败: " + e.getMessage());
            e.printStackTrace();
        }

        return schedules;
    }

    /**
     * 为一批警员生成排班（保留原方法以防需要）
     */
    private List<Schedule> generateScheduleForBatch(List<SysUser> batchUsers, JSONObject params, String department) {
        List<Schedule> schedules = new ArrayList<>();

        try {
            // 收集当前批次警员信息
            List<Map<String, Object>> officersInfo = new ArrayList<>();
            for (SysUser sysUser : batchUsers) {
                Map<String, Object> officerInfo = new HashMap<>();
                officerInfo.put("officerId", sysUser.getUserId());
                officerInfo.put("officerName", sysUser.getNickName());
                officerInfo.put("department", sysUser.getDept() != null ? sysUser.getDept().getDeptName() : department);
                officerInfo.put("unit", department);
                officersInfo.add(officerInfo);
            }

            // 获取班次数据
            ShiftBo shiftBo = new ShiftBo();
            List<ShiftVo> shiftVoList = shiftService.queryList(shiftBo);

            // ObjectMapper mapper = new ObjectMapper();
            // 不再需要JSON序列化，直接使用结构化数据

            // 查询数据库中的实际数据
            String startDate = params.getStr("startDate", "");
            String endDate = params.getStr("endDate", "");
            String dutyType = params.getStr("dutyType", "轮班巡逻");
            String location = params.getStr("preferredLocation", "深圳市福田区");

            // 查询现有排班数据（限制数量，避免提示词过长）
            Schedule querySchedule = new Schedule();
            List<Schedule> existingSchedules = scheduleService.selectScheduleList(querySchedule);
            Map<Long, Integer> officerExperienceMap = new HashMap<>();
            if (existingSchedules != null && !existingSchedules.isEmpty()) {
                // 只统计经验次数，不保存详细历史
                Map<Long, List<Schedule>> tempMap = existingSchedules.stream()
                    .filter(s -> s != null && s.getOfficerId() != null)
                    .limit(20)  // 限制历史记录数量
                    .collect(Collectors.groupingBy(Schedule::getOfficerId));

                for (Map.Entry<Long, List<Schedule>> entry : tempMap.entrySet()) {
                    officerExperienceMap.put(entry.getKey(), Math.min(entry.getValue().size(), 3));
                }
            }

            // 基于巡区负责人进行排班分析
            Map<Long, PatrolAreaAssignment> areaAssignmentMap = analyzePatrolAreaAssignments();

            // 筛选出有负责人的巡区和对应的用户
            List<SysUser> assignedUsers = new ArrayList<>();
            Map<Long, String> officerAreaMap = new HashMap<>();
            Map<Long, String> officerRouteMap = new HashMap<>();

            for (PatrolAreaAssignment assignment : areaAssignmentMap.values()) {
                if (!assignment.getAssignedUsers().isEmpty()) {
                    for (SysUser user : assignment.getAssignedUsers()) {
                        assignedUsers.add(user);
                        officerAreaMap.put(user.getUserId(),
                            assignment.getAreaName() + "(" + assignment.getAreaType() + ")");
                        officerRouteMap.put(user.getUserId(), assignment.getPatrolRoute());
                    }
                }
            }

            if (assignedUsers.isEmpty()) {
                System.out.println("⚠️ 没有找到已分配巡区的负责人，跳过AI排班");
                return schedules; // 返回空列表
            }

            // 更新batchUsers为实际有巡区分配的用户
            batchUsers = assignedUsers;

            // 构建增强的AI提示词
            StringBuilder aiPrompt = new StringBuilder();
            aiPrompt.append("你是专业的警务排班AI助手。请基于以下真实数据为 ").append(batchUsers.size()).append(" 名警员生成智能排班：\n\n");

            aiPrompt.append("=== 排班基本要求 ===\n");
            aiPrompt.append("执勤方式：").append(dutyType).append("\n");
            aiPrompt.append("起始日期：").append(startDate).append("\n");
            aiPrompt.append("结束日期：").append(endDate).append("\n");
            aiPrompt.append("所属部门：").append(department).append("\n");
            aiPrompt.append("巡逻区域：").append(location).append("\n");
            aiPrompt.append("历史排班记录数：").append(existingSchedules != null ? existingSchedules.size() : 0).append(" 条\n\n");

            aiPrompt.append("区域分配：基于实际巡区分配关系\n\n");

            // 添加警员详细信息和历史分析
            aiPrompt.append("=== 警员详细信息 ===\n");
            for (SysUser user : batchUsers) {
                aiPrompt.append("警员：").append(user.getNickName()).append(" (ID: ").append(user.getUserId()).append(")\n");
                aiPrompt.append("  - 部门：").append(user.getDept() != null ? user.getDept().getDeptName() : "未分配").append("\n");
                aiPrompt.append("  - 联系方式：").append(user.getPhonenumber() != null ? user.getPhonenumber() : "未设置").append("\n");

                // 分配的巡区
                String assignedArea = officerAreaMap.getOrDefault(user.getUserId(), "未分配巡区");
                aiPrompt.append("  - 分配巡区：").append(assignedArea).append("\n");

                // 巡逻路线信息
                String patrolRoute = officerRouteMap.getOrDefault(user.getUserId(), "未分配巡逻路线");
                aiPrompt.append("  - 巡逻路线：").append(patrolRoute).append("\n");

                // 简化历史排班分析（避免提示词过长）
                Integer experienceCount = officerExperienceMap.getOrDefault(user.getUserId(), 0);
                if (experienceCount > 0) {
                    aiPrompt.append("  - 排班经验：有经验(").append(experienceCount).append("次)\n");
                } else {
                    aiPrompt.append("  - 排班经验：新警员\n");
                }
                aiPrompt.append("\n");
            }

            aiPrompt.append("=== 可用班次信息 ===\n");
            for (ShiftVo shift : shiftVoList) {
                aiPrompt.append("班次：").append(shift.getShiftName())
                        .append(" (").append(shift.getShiftTimePeriod()).append(")\n");
                aiPrompt.append("  - 岗位类型：").append(shift.getPostType() != null ? shift.getPostType() : "常规岗位").append("\n");
                aiPrompt.append("  - 岗位分类：").append(shift.getPostCategory() != null ? shift.getPostCategory() : "巡逻").append("\n");
                if (shift.getUnit() != null && !shift.getUnit().isEmpty()) {
                    aiPrompt.append("  - 所属单位：").append(shift.getUnit()).append("\n");
                }
                aiPrompt.append("  - 状态：").append(shift.getIsEnabled() == 1 ? "启用" : "禁用").append("\n");
            }
            aiPrompt.append("\n");

            // 计算日期范围
            int dayCount = calculateDaysBetween(startDate, endDate);
            int totalRecordsNeeded = batchUsers.size() * dayCount;

            aiPrompt.append("=== 智能排班规则 ===\n");
            aiPrompt.append("【基本要求】\n");
            aiPrompt.append("1. 时间覆盖：必须为每个警员在").append(startDate).append("到").append(endDate).append("期间的每一天都安排排班\n");
            aiPrompt.append("2. 数量要求：总共需要生成").append(totalRecordsNeeded).append("条排班记录（").append(batchUsers.size()).append("个警员 × ").append(dayCount).append("天）\n");
            aiPrompt.append("3. 时间分配：确保24小时有人值班，合理轮班（早班06:00-14:00，中班14:00-22:00，夜班22:00-06:00）\n");

            aiPrompt.append("\n【工作强度控制】\n");
            aiPrompt.append("4. 每个警员每天工作8小时，避免连续夜班超过2天\n");
            aiPrompt.append("5. 同一警员避免连续工作超过3天，需要安排休息\n");
            aiPrompt.append("6. 优先考虑警员的历史班次偏好，但要保证公平轮换\n");

            aiPrompt.append("\n【区域和任务分配】\n");
            aiPrompt.append("7. 警员已分配到具体巡区，请按照上述巡区信息进行排班\n");
            aiPrompt.append("8. 巡逻路线已通过动态规划算法生成，请直接使用\n");
            aiPrompt.append("9. 有分配巡区的警员优先安排到对应区域\n");
            aiPrompt.append("10. 同一部门的警员应该有合理的班次搭配，确保经验传承\n");

            aiPrompt.append("\n【智能优化策略】\n");
            aiPrompt.append("11. 新警员（无历史记录）应该与经验丰富的警员搭配\n");
            aiPrompt.append("12. 重点区域应该安排经验丰富的警员\n");
            aiPrompt.append("13. 考虑警员的联系方式，便于紧急情况联系\n");
            aiPrompt.append("14. 根据历史数据平衡各班次的人员分配\n");

            aiPrompt.append("\n【巡逻路线和装备配置】\n");
            aiPrompt.append("15. 巡逻路线：已根据巡区分配和岗位坐标自动生成，请直接使用上述提供的路线\n");
            aiPrompt.append("   - 路线已通过动态规划算法优化，确保巡逻效率最高\n");
            aiPrompt.append("   - 如果显示'无需巡逻'，则该区域为定点执勤或无具体巡逻任务\n");
            aiPrompt.append("16. 装备配置：系统将自动分配装备，AI无需生成装备信息\n\n");

            aiPrompt.append("输出要求：\n");
            aiPrompt.append("1. 只返回JSON格式数据，不要任何解释文字\n");
            aiPrompt.append("2. 不要使用markdown代码块\n");
            aiPrompt.append("3. 直接返回纯JSON对象\n\n");

            aiPrompt.append("=== 返回格式要求 ===\n");
            aiPrompt.append("【格式说明】\n");
            aiPrompt.append("- 只返回JSON格式数据，不要任何解释文字或markdown代码块\n");
            aiPrompt.append("- 直接返回纯JSON对象，确保格式正确\n");
            aiPrompt.append("- 所有字段都必须填写，不能为空\n\n");

            aiPrompt.append("【JSON结构】\n");
            aiPrompt.append("🚨 关键要求：scheduleDate字段必须使用具体日期，不能为空！\n");
            aiPrompt.append("{\n");
            aiPrompt.append("  \"schedules\": [\n");
            aiPrompt.append("    {\n");
            aiPrompt.append("      \"officerName\": \"警员姓名\",\n");
            aiPrompt.append("      \"officerId\": 警员ID数字,\n");
            aiPrompt.append("      \"scheduleDate\": \"").append(startDate).append("\",\n");
            aiPrompt.append("      \"shiftName\": \"早班/中班/夜班\",\n");
            aiPrompt.append("      \"timePeriod\": \"06:00-14:00\",\n");
            aiPrompt.append("      \"reason\": \"AI智能排班-基于历史数据分析\"\n");
            aiPrompt.append("    }\n");
            aiPrompt.append("  ]\n");
            aiPrompt.append("}\n\n");
            aiPrompt.append("⚠️ 特别注意：scheduleDate字段必须使用").append(startDate).append("到").append(endDate).append("范围内的具体日期！\n\n");

            aiPrompt.append("【数据完整性检查】\n");
            aiPrompt.append("🚨 日期要求（最重要）：\n");
            aiPrompt.append("- scheduleDate字段绝对不能为空字符串\n");
            aiPrompt.append("- scheduleDate必须使用具体日期，格式：YYYY-MM-DD\n");
            aiPrompt.append("- 日期必须在指定范围内：").append(startDate).append(" 到 ").append(endDate).append("\n");
            aiPrompt.append("- 每条记录的scheduleDate都必须有值\n\n");
            aiPrompt.append("📊 数量要求：\n");
            aiPrompt.append("- 必须为每个警员生成").append(dayCount).append("天的排班记录\n");
            aiPrompt.append("- 总记录数必须等于").append(totalRecordsNeeded).append("条\n");
            aiPrompt.append("- 每个警员的每一天都必须有排班安排\n");
            aiPrompt.append("- 不能遗漏任何警员或任何日期\n\n");
            aiPrompt.append("🔍 数据质量要求：\n");
            aiPrompt.append("- 警员ID必须使用提供的真实ID，不能编造\n");
            aiPrompt.append("- 班次名称必须使用数据库中存在的班次\n");
            aiPrompt.append("- 所有字段都必须有值，不能为空\n\n");

            aiPrompt.append("【质量要求】\n");
            aiPrompt.append("- 排班应该体现智能化：考虑历史偏好、工作强度、区域分配\n");
            aiPrompt.append("- 新警员应该与有经验的警员搭配\n");
            aiPrompt.append("- 重点区域应该安排经验丰富的警员\n");
            aiPrompt.append("- 班次分配应该相对均衡，避免某个班次人员过多或过少\n\n");

            // 实现按天生成排班，避免JSON过长被截断
            List<String> dateList = generateDateList(startDate, endDate);

            // 按天生成排班
            for (String targetDate : dateList) {
                System.out.println("生成 " + targetDate + " 的排班...");

                // 构建单日排班提示词
                String dailyPrompt = buildDailyPrompt(batchUsers, shiftVoList, targetDate, officerExperienceMap, officerAreaMap);

                // 调用AI接口
                String result = deepSeekService.askAI(dailyPrompt);

                // 处理单日排班结果（包含清理和插入逻辑）
                processDailyScheduleResult(result, schedules, batchUsers, targetDate, params, officerRouteMap, officerAreaMap);
            }

            System.out.println("按天生成排班完成，总记录数: " + schedules.size());
        } catch (Exception e) {
            System.out.println("批次排班生成失败: " + e.getMessage());
            e.printStackTrace();
        }

        return schedules;
    }







    /**
     * 计算两个日期之间的天数
     */
    private int calculateDaysBetween(String startDate, String endDate) {
        try {
            if (startDate == null || startDate.isEmpty() || endDate == null || endDate.isEmpty()) {
                return 1; // 默认1天
            }

            java.time.LocalDate start = java.time.LocalDate.parse(startDate);
            java.time.LocalDate end = java.time.LocalDate.parse(endDate);

            return (int) java.time.temporal.ChronoUnit.DAYS.between(start, end) + 1; // +1 包含结束日期
        } catch (Exception e) {
            System.out.println("日期解析错误: " + e.getMessage());
            return 1; // 默认1天
        }
    }

    public static String extractJsonArray(String rawText) {
        int startIndex = rawText.indexOf('[');
        int endIndex = rawText.lastIndexOf(']');

        if (startIndex >= 0 && endIndex > startIndex) {
            return rawText.substring(startIndex, endIndex + 1);
        } else {
            throw new IllegalArgumentException("输入中不包含合法的 JSON 数组");
        }
    }

    /**
     * 生成日期列表
     */
    private List<String> generateDateList(String startDate, String endDate) {
        List<String> dateList = new ArrayList<>();
        try {
            java.time.LocalDate start = java.time.LocalDate.parse(startDate);
            java.time.LocalDate end = java.time.LocalDate.parse(endDate);

            java.time.LocalDate current = start;
            while (!current.isAfter(end)) {
                dateList.add(current.toString());
                current = current.plusDays(1);
            }
        } catch (Exception e) {
            System.out.println("日期解析错误: " + e.getMessage());
            dateList.add(startDate); // 默认添加开始日期
        }
        return dateList;
    }

    /**
     * 清理指定日期范围内的AI生成记录
     */
    private void cleanupExistingSchedules(String startDate, String endDate) {
        try {
            // 构建查询条件，删除指定日期范围内的AI生成记录
            Schedule querySchedule = new Schedule();
            List<Schedule> existingSchedules = scheduleService.selectScheduleList(querySchedule);

            // 筛选出需要删除的记录（指定日期范围内的AI生成记录）
            List<Long> idsToDelete = new ArrayList<>();
            java.time.LocalDate start = java.time.LocalDate.parse(startDate);
            java.time.LocalDate end = java.time.LocalDate.parse(endDate);

            for (Schedule schedule : existingSchedules) {
                if (schedule.getScheduleDate() != null) {
                    java.time.LocalDate scheduleDate = schedule.getScheduleDate().toInstant()
                        .atZone(java.time.ZoneId.systemDefault()).toLocalDate();

                    // 检查是否在指定日期范围内，且是AI生成的记录
                    if (!scheduleDate.isBefore(start) && !scheduleDate.isAfter(end)) {
                        // 可以通过创建者或其他字段判断是否为AI生成，这里简化处理
                        idsToDelete.add(schedule.getId());
                    }
                }
            }

            // 批量删除
            if (!idsToDelete.isEmpty()) {
                for (Long id : idsToDelete) {
                    scheduleService.delete(id);
                }
                System.out.println("清理了 " + idsToDelete.size() + " 条旧的排班记录 (" + startDate + " 到 " + endDate + ")");
            } else {
                System.out.println("没有找到需要清理的记录");
            }
        } catch (Exception e) {
            System.out.println("清理记录失败: " + e.getMessage());
        }
    }

    /**
     * 清理指定单日的排班记录
     */
    private void cleanupDailySchedules(String targetDate) {
        try {
            // 查询所有排班记录
            Schedule querySchedule = new Schedule();
            List<Schedule> existingSchedules = scheduleService.selectScheduleList(querySchedule);

            // 筛选出需要删除的记录（指定日期的记录）
            List<Long> idsToDelete = new ArrayList<>();
            java.time.LocalDate target = java.time.LocalDate.parse(targetDate);

            for (Schedule schedule : existingSchedules) {
                if (schedule.getScheduleDate() != null) {
                    java.time.LocalDate scheduleDate = schedule.getScheduleDate().toInstant()
                        .atZone(java.time.ZoneId.systemDefault()).toLocalDate();

                    // 检查是否是指定日期的记录
                    if (scheduleDate.equals(target)) {
                        idsToDelete.add(schedule.getId());
                    }
                }
            }

            // 批量删除
            if (!idsToDelete.isEmpty()) {
                for (Long id : idsToDelete) {
                    scheduleService.delete(id);
                }
                System.out.println("🧹 清理了 " + idsToDelete.size() + " 条 " + targetDate + " 的旧排班记录");
            } else {
                System.out.println("📝 " + targetDate + " 没有找到需要清理的记录");
            }
        } catch (Exception e) {
            System.out.println("❌ 清理 " + targetDate + " 记录失败: " + e.getMessage());
        }
    }

    /**
     * 为已分配用户构建单日排班提示词
     */
    private String buildDailyPromptForAssignedUsers(List<SysUser> assignedUsers, List<ShiftVo> shiftVoList, String targetDate,
                                                   Map<Long, Integer> officerExperienceMap, Map<Long, String> officerAreaMap,
                                                   Map<Long, String> officerRouteMap) {
        StringBuilder prompt = new StringBuilder();

        prompt.append("你是专业的警务排班AI助手。请基于以下真实巡区分配数据为 ").append(assignedUsers.size()).append(" 名警员生成智能排班：\n\n");

        prompt.append("=== 排班日期 ===\n");
        prompt.append("目标日期：").append(targetDate).append("\n\n");

        prompt.append("=== 警员信息（基于巡区分配）===\n");
        for (int i = 0; i < assignedUsers.size(); i++) {
            SysUser user = assignedUsers.get(i);
            prompt.append((i + 1)).append(". 警员：").append(user.getNickName())
                  .append("（ID: ").append(user.getUserId()).append("）\n");
            prompt.append("   - 部门：").append(user.getDept() != null ? user.getDept().getDeptName() : "未知").append("\n");
            prompt.append("   - 分配巡区：").append(officerAreaMap.getOrDefault(user.getUserId(), "未分配")).append("\n");
            prompt.append("   - 巡逻路线：").append(officerRouteMap.getOrDefault(user.getUserId(), "未设置")).append("\n");

            int experience = officerExperienceMap.getOrDefault(user.getUserId(), 0);
            prompt.append("   - 排班经验：").append(experience > 0 ? experience + "次" : "新警员").append("\n\n");
        }

        prompt.append("=== 可用班次 ===\n");
        for (ShiftVo shift : shiftVoList) {
            prompt.append("- ").append(shift.getShiftName()).append("：").append(shift.getShiftTimePeriod()).append("\n");
        }

        prompt.append("\n=== 排班要求 ===\n");
        prompt.append("1. 每个警员必须分配一个班次\n");
        prompt.append("2. 巡区和巡逻路线已确定，AI只需分配班次时间\n");
        prompt.append("3. 考虑警员经验，新警员优先安排早班或白班\n");
        prompt.append("4. 确保时间覆盖合理，避免空档期\n");
        prompt.append("5. 装备配置由系统自动生成，无需AI处理\n\n");

        prompt.append("=== 输出格式 ===\n");
        prompt.append("请严格按照以下JSON格式输出，不要添加任何其他内容：\n");
        prompt.append("{\n");
        prompt.append("  \"schedules\": [\n");
        prompt.append("    {\n");
        prompt.append("      \"officerName\": \"警员姓名\",\n");
        prompt.append("      \"officerId\": 警员ID,\n");
        prompt.append("      \"scheduleDate\": \"").append(targetDate).append("\",\n");
        prompt.append("      \"shiftName\": \"早班/中班/夜班\",\n");
        prompt.append("      \"timePeriod\": \"06:00-14:00\",\n");
        prompt.append("      \"reason\": \"AI智能排班-基于巡区分配\"\n");
        prompt.append("    }\n");
        prompt.append("  ]\n");
        prompt.append("}\n\n");

        prompt.append("注意：\n");
        prompt.append("1. 必须为所有 ").append(assignedUsers.size()).append(" 名警员生成排班\n");
        prompt.append("2. 巡区和路线信息已在上述信息中提供，请直接使用\n");
        prompt.append("3. 只输出JSON，不要添加任何解释或其他文字\n");

        return prompt.toString();
    }

    /**
     * 构建单日排班提示词
     */
    private String buildDailyPrompt(List<SysUser> batchUsers, List<ShiftVo> shiftVoList,
                                   String targetDate, Map<Long, Integer> officerExperienceMap,
                                   Map<Long, String> officerAreaMap) {
        StringBuilder prompt = new StringBuilder();

        prompt.append("# 🚔 警务单日排班系统\n\n");
        prompt.append("## 📋 任务目标\n");
        prompt.append("为 ").append(batchUsers.size()).append(" 名警员生成 ").append(targetDate).append(" 的排班计划\n\n");

        prompt.append("## 🎯 核心要求\n");
        prompt.append("- **总记录数**: 必须生成 ").append(batchUsers.size()).append(" 条记录\n");
        prompt.append("- **日期**: ").append(targetDate).append("\n");
        prompt.append("- **每人一班**: 每个警员必须有且仅有一条排班记录\n\n");

        prompt.append("## 👮‍♂️ 警员信息\n");
        for (int i = 0; i < batchUsers.size(); i++) {
            SysUser user = batchUsers.get(i);
            String deptInfo = user.getDept() != null ? user.getDept().getDeptName() : "未分配";
            String areaInfo = officerAreaMap.getOrDefault(user.getUserId(), "未分配区域");
            Integer experienceCount = officerExperienceMap.getOrDefault(user.getUserId(), 0);
            String historyInfo = experienceCount > 0 ? "有经验(" + experienceCount + "次)" : "新警员";

            prompt.append(String.format("%d. **%s** (ID: %d)\n", i + 1, user.getNickName(), user.getUserId()));
            prompt.append("    - 部门: ").append(deptInfo).append("\n");
            prompt.append("    - 区域: ").append(areaInfo).append("\n");
            prompt.append("    - 经验: ").append(historyInfo).append("\n");
        }

        prompt.append("\n## ⏰ 可用班次\n");
        for (int i = 0; i < shiftVoList.size(); i++) {
            ShiftVo shift = shiftVoList.get(i);
            String timePeriod = shift.getShiftTimePeriod() != null ? shift.getShiftTimePeriod() : "待定";
            prompt.append(String.format("%d. **%s** (%s)\n", i + 1, shift.getShiftName(), timePeriod));
        }

        prompt.append("\n## 🎯 排班要求\n");
        prompt.append("1. 为每个警员分配一个班次\n");
        prompt.append("2. 确保24小时覆盖\n");
        prompt.append("3. 重点区域安排有经验的警员\n");
        prompt.append("4. 班次分配要均衡\n\n");

        prompt.append("## 💻 输出格式\n");
        prompt.append("🚨 严格要求：\n");
        prompt.append("1. 直接返回JSON，不要markdown标记\n");
        prompt.append("2. scheduleDate字段必须使用：").append(targetDate).append("\n");
        prompt.append("3. 所有字段都必须有值，不能为空\n");
        prompt.append("4. officerId必须是数字类型\n\n");
        prompt.append("{\n");
        prompt.append("  \"schedules\": [\n");
        prompt.append("    {\n");
        prompt.append("      \"officerName\": \"警员姓名\",\n");
        prompt.append("      \"officerId\": 警员ID数字,\n");
        prompt.append("      \"scheduleDate\": \"").append(targetDate).append("\",\n");
        prompt.append("      \"shiftName\": \"早班/中班/夜班\",\n");
        prompt.append("      \"timePeriod\": \"06:00-14:00\",\n");
        prompt.append("      \"reason\": \"AI智能排班\"\n");
        prompt.append("    }\n");
        prompt.append("  ]\n");
        prompt.append("}\n\n");
        prompt.append("⚠️ 重要：scheduleDate必须是").append(targetDate).append("，不能为空！\n\n");

        prompt.append("请为所有 ").append(batchUsers.size()).append(" 名警员生成 ").append(targetDate).append(" 的排班，总共 ").append(batchUsers.size()).append(" 条记录：");

        return prompt.toString();
    }

    /**
     * 处理单日排班结果
     */
    private void processDailyScheduleResult(String result, List<Schedule> schedules,
                                          List<SysUser> batchUsers, String targetDate,
                                          JSONObject params, Map<Long, String> officerRouteMap,
                                          Map<Long, String> officerAreaMap) {
        try {
            // 解析AI返回结果
            JSONObject resultJsonObject = new JSONObject(result);
            JSONObject choices = (JSONObject) resultJsonObject.getJSONArray("choices").get(0);
            String content = choices.getJSONObject("message").getStr("content");

            // 清理AI返回内容
            String cleanedJson = content.replaceAll("(?s)```json\\s*|```", "").trim();
            int jsonStart = cleanedJson.indexOf("{");
            int jsonEnd = cleanedJson.lastIndexOf("}") + 1;

            if (jsonStart >= 0 && jsonEnd > jsonStart) {
                cleanedJson = cleanedJson.substring(jsonStart, jsonEnd);
            }

            System.out.println("清理后的JSON: " + cleanedJson);

            // 解析JSON
            JSONObject responseObj = new JSONObject(cleanedJson);
            JSONArray scheduleList = null;

            if (responseObj.containsKey("schedules")) {
                scheduleList = responseObj.getJSONArray("schedules");
            } else if (cleanedJson.startsWith("[")) {
                scheduleList = new JSONArray(cleanedJson);
            } else {
                scheduleList = new JSONArray("[" + cleanedJson + "]");
            }

            // 🔥 关键改进：成功解析JSON后，不再重复清理（已在开始时清理过）
            System.out.println("✅ JSON解析成功，开始处理排班记录...");

            // 处理每个排班记录
            for (Object scheduleObj : scheduleList) {
                JSONObject jsonObject = (JSONObject) scheduleObj;
                Schedule schedule = new Schedule();

                // 获取警员信息
                String officerName = jsonObject.getStr("officerName");
                Long officerIdVal = null;

                // 尝试从AI返回的数据中获取officerId
                Object officerIdObj = jsonObject.get("officerId");
                if (officerIdObj != null) {
                    try {
                        if (officerIdObj instanceof Number) {
                            officerIdVal = ((Number) officerIdObj).longValue();
                        } else {
                            officerIdVal = Long.parseLong(officerIdObj.toString());
                        }
                    } catch (NumberFormatException e) {
                        System.out.println("警员ID解析失败: " + officerIdObj + ", 警员姓名: " + officerName);
                    }
                }

                // 如果AI返回的ID无效，尝试根据姓名匹配
                if (officerIdVal == null && officerName != null) {
                    for (SysUser user : batchUsers) {
                        if (officerName.equals(user.getNickName()) || officerName.equals(user.getUserName())) {
                            officerIdVal = user.getUserId();
                            break;
                        }
                    }
                }

                // 如果仍然无法匹配，跳过这条记录
                if (officerIdVal == null) {
                    System.out.println("无法匹配警员ID，跳过记录: " + officerName);
                    continue;
                }

                schedule.setOfficerId(officerIdVal);
                schedule.setOfficerName(officerName);
                schedule.setDutyType(params.getStr("dutyType", "巡逻"));
                schedule.setTimePeriod(jsonObject.getStr("timePeriod"));
                schedule.setShiftName(jsonObject.getStr("shiftName"));
                schedule.setScene(params.getStr("scenario", "社区巡逻"));

                // 设置日期
                try {
                    schedule.setScheduleDate(DateUtils.parseDate(targetDate));
                } catch (Exception e) {
                    schedule.setScheduleDate(DateUtils.parseDate(params.getStr("startDate")));
                }

                // 设置巡逻路线和装备配置
                // 优先使用预生成的巡逻路线
                String preGeneratedRoute = officerRouteMap.getOrDefault(officerIdVal, "待分配路线");
                schedule.setRoute(preGeneratedRoute);

                // 本地生成装备配置
                String equipment = generateEquipment(jsonObject.getStr("shiftName"),
                    officerAreaMap.getOrDefault(officerIdVal, ""));
                schedule.setEquipments(equipment);

                // 🔧 修复：设置巡逻地点为用户分配的具体巡区，而不是固定的"深圳市"
                String assignedArea = officerAreaMap.getOrDefault(officerIdVal, "未分配巡区");
                schedule.setPoints(assignedArea);
                schedule.setReason(jsonObject.getStr("reason", "AI智能排班"));

                schedules.add(schedule);
                System.out.println("添加排班记录: " + schedule.getOfficerName() + " - " + schedule.getShiftName() + " (" + targetDate + ")");
            }

            // 🔥 关键改进：立即保存当天的新排班记录
            if (!schedules.isEmpty()) {
                // 筛选出当天的记录
                List<Schedule> dailySchedules = schedules.stream()
                    .filter(s -> {
                        try {
                            java.time.LocalDate scheduleDate = s.getScheduleDate().toInstant()
                                .atZone(java.time.ZoneId.systemDefault()).toLocalDate();
                            return scheduleDate.equals(java.time.LocalDate.parse(targetDate));
                        } catch (Exception e) {
                            return false;
                        }
                    })
                    .collect(java.util.stream.Collectors.toList());

                if (!dailySchedules.isEmpty()) {
                    // 保存当天的排班记录
                    scheduleService.batchSaveSchedule(dailySchedules);
                    System.out.println("💾 成功保存 " + targetDate + " 的 " + dailySchedules.size() + " 条排班记录");
                }
            }

        } catch (Exception e) {
            System.out.println("处理单日排班结果失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 清理指定日期范围内的所有排班记录
     */
    private void cleanupDateRangeSchedules(String startDate, String endDate) {
        try {
            System.out.println("🔍 开始查询现有排班记录...");

            // 使用正确的查询方法查询所有排班记录
            Schedule querySchedule = new Schedule();
            List<Schedule> existingSchedules = scheduleService.queryScheduleList(querySchedule);

            if (existingSchedules == null || existingSchedules.isEmpty()) {
                System.out.println("📝 查询结果为空，没有现有排班记录");
                return;
            }

            System.out.println("📊 查询到 " + existingSchedules.size() + " 条现有排班记录");

            // 筛选出需要删除的记录（指定日期范围内的记录）
            List<Long> idsToDelete = new ArrayList<>();
            java.time.LocalDate start = java.time.LocalDate.parse(startDate);
            java.time.LocalDate end = java.time.LocalDate.parse(endDate);

            System.out.println("🎯 筛选日期范围: " + start + " 到 " + end);

            for (Schedule schedule : existingSchedules) {
                try {
                    if (schedule != null && schedule.getId() != null && schedule.getScheduleDate() != null) {
                        java.time.LocalDate scheduleDate = schedule.getScheduleDate().toInstant()
                            .atZone(java.time.ZoneId.systemDefault()).toLocalDate();

                        // 检查是否在指定日期范围内
                        if (!scheduleDate.isBefore(start) && !scheduleDate.isAfter(end)) {
                            idsToDelete.add(schedule.getId());
                            System.out.println("🎯 标记删除: ID=" + schedule.getId() + ", 日期=" + scheduleDate + ", 警员=" + schedule.getOfficerName());
                        }
                    }
                } catch (Exception e) {
                    System.out.println("⚠️ 处理单条记录时出错: " + e.getMessage());
                }
            }

            // 批量删除
            if (!idsToDelete.isEmpty()) {
                System.out.println("🗑️ 开始删除 " + idsToDelete.size() + " 条记录...");
                int deletedCount = 0;

                for (Long id : idsToDelete) {
                    try {
                        boolean deleted = scheduleService.delete(id);
                        if (deleted) {
                            deletedCount++;
                            System.out.println("✅ 删除成功: ID=" + id);
                        } else {
                            System.out.println("❌ 删除失败: ID=" + id);
                        }
                    } catch (Exception e) {
                        System.out.println("❌ 删除记录 " + id + " 时出错: " + e.getMessage());
                    }
                }

                System.out.println("🧹 清理完成！成功删除 " + deletedCount + "/" + idsToDelete.size() + " 条日期范围 " + startDate + " 到 " + endDate + " 的排班记录");
            } else {
                System.out.println("📝 日期范围 " + startDate + " 到 " + endDate + " 没有找到需要清理的记录");
            }
        } catch (Exception e) {
            System.out.println("❌ 清理日期范围记录失败: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName()));
            e.printStackTrace();
        }
    }

    /**
     * 手动清理重复记录的API接口
     */
    @PostMapping("/cleanup/duplicates")
    public R<Void> cleanupDuplicates(@RequestBody JSONObject params) {
        try {
            String startDate = params.getStr("startDate", "");
            String endDate = params.getStr("endDate", "");

            if (startDate.isEmpty() || endDate.isEmpty()) {
                return R.fail("请指定清理的日期范围");
            }

            cleanupDateRangeSchedules(startDate, endDate);
            return R.ok("重复记录清理完成");
        } catch (Exception e) {
            System.out.println("清理重复记录失败: " + e.getMessage());
            return R.fail("清理失败：" + e.getMessage());
        }
    }

    /**
     * 分析巡区分配情况，生成巡逻路线
     */
    private Map<Long, PatrolAreaAssignment> analyzePatrolAreaAssignments() {
        Map<Long, PatrolAreaAssignment> assignmentMap = new HashMap<>();

        try {
            // 获取所有巡区
            List<PatrolAreaVo> areas = patrolAreaService.queryList(new com.ruoyi.system.domain.bo.PatrolAreaBo());

            for (PatrolAreaVo area : areas) {
                PatrolAreaAssignment assignment = new PatrolAreaAssignment();
                assignment.setAreaId(area.getAreaId());
                assignment.setAreaName(area.getAreaName());
                assignment.setAreaType(area.getAreaType() == 2 ? "重点区域" : "常规区域");

                // 获取该巡区的负责人
                List<PatrolAreaUserVo> areaUsers = patrolAreaUserService.queryByAreaId(area.getAreaId());
                List<SysUser> assignedUsers = new ArrayList<>();

                for (PatrolAreaUserVo areaUser : areaUsers) {
                    if (areaUser.getAssignType() == 1) { // 只获取主要负责人
                        SysUser user = sysUserService.selectUserById(areaUser.getUserId());
                        if (user != null) {
                            assignedUsers.add(user);
                        }
                    }
                }
                assignment.setAssignedUsers(assignedUsers);

                // 获取该巡区的岗位点位
                List<PostVo> areaPosts = getPostsByArea(area);
                assignment.setAvailablePosts(areaPosts);

                // 生成巡逻路线
                String patrolRoute = generatePatrolRoute(areaPosts);
                assignment.setPatrolRoute(patrolRoute);

                assignmentMap.put(area.getAreaId(), assignment);

                System.out.println("巡区分析: " + area.getAreaName() +
                    ", 负责人数: " + assignedUsers.size() +
                    ", 岗位数: " + areaPosts.size() +
                    ", 路线: " + patrolRoute);
            }

        } catch (Exception e) {
            System.out.println("分析巡区分配失败: " + e.getMessage());
        }

        return assignmentMap;
    }

    /**
     * 根据巡区获取对应的岗位
     */
    private List<PostVo> getPostsByArea(PatrolAreaVo area) {
        try {
            PostBo postBo = new PostBo();

            // 1. 优先按巡区名称匹配
            postBo.setPostCategory(area.getAreaName());
            List<PostVo> posts = postService.queryList(postBo);

            // 2. 如果没找到，按类型匹配
            if (posts.isEmpty()) {
                postBo = new PostBo();
                if (area.getAreaType() == 2) {
                    postBo.setPostType("重点岗");
                } else {
                    postBo.setPostType("固定岗");
                }
                posts = postService.queryList(postBo);
            }

            return posts;
        } catch (Exception e) {
            System.out.println("获取巡区岗位失败: " + e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 生成巡逻路线（动态规划算法）
     */
    private String generatePatrolRoute(List<PostVo> posts) {
        if (posts.isEmpty()) {
            return "无需巡逻";
        }

        if (posts.size() == 1) {
            return posts.get(0).getPostName() + " 定点执勤";
        }

        // 使用最近邻算法生成路线
        List<PostVo> route = new ArrayList<>();
        List<PostVo> remaining = new ArrayList<>(posts);

        // 从第一个岗位开始
        PostVo current = remaining.remove(0);
        route.add(current);

        while (!remaining.isEmpty()) {
            PostVo nearest = findNearestPost(current, remaining);
            if (nearest != null) {
                route.add(nearest);
                remaining.remove(nearest);
                current = nearest;
            } else {
                // 如果没有坐标信息，直接按顺序添加
                route.addAll(remaining);
                break;
            }
        }

        // 生成路线描述
        StringBuilder routeDesc = new StringBuilder();
        for (int i = 0; i < route.size(); i++) {
            if (i > 0) routeDesc.append(" → ");
            routeDesc.append(route.get(i).getPostName());
        }

        if (route.size() > 1) {
            routeDesc.append(" → 返回起点");
        }

        return routeDesc.toString();
    }

    /**
     * 找到距离当前岗位最近的岗位
     */
    private PostVo findNearestPost(PostVo current, List<PostVo> candidates) {
        if (current.getLatitude() == null || current.getLongitude() == null) {
            return candidates.isEmpty() ? null : candidates.get(0);
        }

        PostVo nearest = null;
        double minDistance = Double.MAX_VALUE;

        for (PostVo candidate : candidates) {
            if (candidate.getLatitude() != null && candidate.getLongitude() != null) {
                double distance = calculateDistance(
                    current.getLatitude().doubleValue(), current.getLongitude().doubleValue(),
                    candidate.getLatitude().doubleValue(), candidate.getLongitude().doubleValue()
                );

                if (distance < minDistance) {
                    minDistance = distance;
                    nearest = candidate;
                }
            }
        }

        return nearest != null ? nearest : (candidates.isEmpty() ? null : candidates.get(0));
    }

    /**
     * 计算两点间距离（Haversine公式）
     */
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径（公里）

        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return R * c;
    }

    /**
     * 本地生成装备配置
     */
    private String generateEquipment(String shiftName, String areaInfo) {
        List<String> basicEquipment = new ArrayList<>();

        // 基础装备（所有班次都有）
        basicEquipment.add("对讲机");
        basicEquipment.add("执法记录仪");

        // 根据班次添加特定装备
        if ("早班".equals(shiftName)) {
            basicEquipment.add("记录本");
            basicEquipment.add("体温计");
        } else if ("中班".equals(shiftName)) {
            basicEquipment.add("警棍");
            basicEquipment.add("手铐");
        } else if ("夜班".equals(shiftName)) {
            basicEquipment.add("警棍");
            basicEquipment.add("手电筒");
            basicEquipment.add("反光背心");
        }

        // 根据区域类型添加特殊装备
        if (areaInfo.contains("重点区域")) {
            basicEquipment.add("防护装备");
            basicEquipment.add("应急设备");
        }

        // 随机添加一些额外装备
        List<String> optionalEquipment = Arrays.asList(
            "急救包", "雨衣", "口哨", "测温枪", "消毒液", "手套"
        );

        // 随机选择1-2个额外装备
        Collections.shuffle(optionalEquipment);
        int extraCount = (int)(Math.random() * 2) + 1;
        for (int i = 0; i < Math.min(extraCount, optionalEquipment.size()); i++) {
            basicEquipment.add(optionalEquipment.get(i));
        }

        return String.join("、", basicEquipment);
    }

}
